/*
 * Implementacion del Arbol Sintactico para el lenguaje C Minus.
 * 
 * Basado en el proyecto descrito en: 
 * Louden, K. (1997). Compiler Construction: Principles and Practice. Boston: PWS.
 * 
 * @ Project: Compiler
 * @ File Name: SynNode.java
 */
package cml.parsing.tree;

import java.util.ArrayList;

public abstract class SynNode {
	
	protected ArrayList<SynNode> childs;
	protected SynNode sibling;
	protected int lineNo;
	private static int tabNum = -1;
	
	/*
	 * Constructor de la clase.
	 */
	protected SynNode() {
		
		this.sibling = null;
		this.lineNo = -1;
	}
	
	/*
	 * Agrega un hijo.
	 * 
	 * @param	child	nodo hijo
	 */
	public void addChild(SynNode child) {
		
		this.childs.add(child);
	}
	
	/*
	 * Agrega un hijo en la posicion indicada
	 * 
	 * @param	child	nodo hijo
	 * @param	index	posicion
	 */
	public void setChild(SynNode child, int index) {
		
		this.childs.set(index, child);
	}
	
	/*
	 * Agrega al hermano.
	 * 
	 * @param	sibling	nodo hermano
	 */
	public void setSibling(SynNode sibling) {
		
		this.sibling = sibling;
	}
	
	/*
	 * Establece el numero de linea.
	 * 
	 * @param	lineNo	numero de linea
	 */
	public void setLineNo(int lineNo) {
		
		this.lineNo = lineNo;
	}
	
	/*
	 * Regresa al hijo de la posicion indicada.
	 * 
	 * @param	index	posicion
	 * @return	nodo hijo
	 */
	public SynNode getChild(int index) {
		
		return this.childs.get(index);
	}
	
	/*
	 * Regresa al hermano.
	 * 
	 * @return	nodo hermano
	 */
	public SynNode getSibling() {
		
		return this.sibling;
	}
	
	/*
	 * Regresa el numero de linea.
	 * 
	 * @return	numero de linea
	 */
	public int getLineNo() {
	
		return this.lineNo;
	}	
	
	/*
	 * Regresa el numero de hijos.
	 * 
	 * @return	numero de hijos
	 */
	public int getChildCount() {
		
		return this.childs.size();
	}
	
	/*
	 * Imprime el arbol sintactico completo.
	 */
	public static void printTree(SynNode tree) {
		
		tabNum++;
		
		while(tree != null) {
			
			printTabs();
			
			int ln = tree.getLineNo() + 1;
			
			System.out.print(ln + "| ");
			
			if(tree instanceof DeclNode) {
				
				DeclNode temp = (DeclNode)tree;
				
				if(tree instanceof VarDeclNode)
					System.out.println("Decl. Variable: " + temp.getName());
				else if(tree instanceof FuncDeclNode)
					System.out.println("Decl. Funcion: " + temp.getName());
				else if(tree instanceof ParamNode)
					System.out.println("Parametro: " + temp.getName());
			}
			else if(tree instanceof StmtNode) {
				
				if(tree instanceof IfNode)
					System.out.println("Si");
				else if(tree instanceof ElseNode)
					System.out.println("Sino");
				else if(tree instanceof ForNode)
					System.out.println("Para");
				else if(tree instanceof WhileNode)
					System.out.println("Mientras");
				else if(tree instanceof ReturnNode)
					System.out.println("Regresa");
			}
			else if(tree instanceof ExpNode) {
				
				if(tree instanceof OpNode) {
					
					OpNode temp = (OpNode)tree;
					System.out.println("Operador: " + temp.getName());
				}
				else if(tree instanceof TypeNode) {
					
					TypeNode temp = (TypeNode)tree;
					System.out.println("Tipo: " + temp.getType());
				}
				else if(tree instanceof NumNode) {
					
					NumNode temp = (NumNode)tree;
					Object value = temp.getValue();
					
					if(value instanceof Integer) {
						
						Integer v = (Integer)value;
						System.out.println("Entero: " + v);
					}
					else if (value instanceof Double) {
						
						Double v = (Double)value;
						System.out.println("Decimal: " + v);
					}
				}
				else if(tree instanceof BoolNode) {
					
					BoolNode temp = (BoolNode)tree;
					System.out.println("Booleano: " + temp.getValue());
				}
				else if(tree instanceof TextNode) {
					
					TextNode temp = (TextNode)tree;
					System.out.println("Texto: " + temp.getValue());
				}
				else if(tree instanceof VarNode) {
					
					VarNode temp = (VarNode)tree;
					System.out.println("Variable: " + temp.getName());
				}
				else if(tree instanceof CallNode) {
					
					CallNode temp = (CallNode)tree;
					System.out.println("Llamada: " + temp.getName());
				}
			}
			
			for(int i = 0; i < tree.getChildCount(); i++)
				printTree(tree.getChild(i));
			
			tree = tree.getSibling();
		}
		
		tabNum--;
	}
	
	/*
	 * Imprime indentaciones.
	 */
	private static void printTabs() {
		
		for(int i = 0; i < tabNum; i++)
			System.out.print("\t");
	}
}
